// TreeManager.cpp: implementation of the CTreeManager class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "TreeManager.h"
#include "TreeNode.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CTreeManager::CTreeManager()
	:m_pRootNode(0),
	m_bTraversing(FALSE)
{
	
}

CTreeManager::~CTreeManager()
{
	CleanTree();
}

void CTreeManager::CleanTree()
{
	if (NULL == m_pRootNode)
	{
		return;
	}	
	delete m_pRootNode;
	m_pRootNode = NULL;
}

BOOL CTreeManager::IsTraversing()
{
	return m_bTraversing;
}

BOOL CTreeManager::CreateTree(CString csFilePath, lpTraverseCallback pCallbackFun, LPVOID lParam)
{
	ASSERT(!csFilePath.IsEmpty());
	CleanTree();
	ASSERT(NULL == m_pRootNode);
	m_bTraversing = TRUE;

	//create root node
	m_pRootNode = new CTreeNode;
	CString csRootPath = RemoveBackSlash(csFilePath);
// 	csRootPath += _T("\\*");
	m_pRootNode->csName = csRootPath;

	//node queue
	CArray<CTreeNode*, CTreeNode*> arrNode;
	arrNode.Add(m_pRootNode);

	//
	int nSizeArr = arrNode.GetSize();
	while (nSizeArr > 0)
	{
		CTreeNode* pCurNode = arrNode.GetAt(0);
		ASSERT(NULL != pCurNode);	
		CString csCurPath = GetFullPath(pCurNode);
		csCurPath += _T("\\*");
		//
		WIN32_FIND_DATA FindFileData;
		memset(&FindFileData, 0, sizeof(WIN32_FIND_DATA));
		HANDLE hFind;
		hFind = FindFirstFile(csCurPath, &FindFileData);
		if (INVALID_HANDLE_VALUE == hFind)
		{
			int nSize = pCurNode->pParent->arrSubNode.GetSize();
			int i;
			for(i=0; i<nSize; i++)
			{
				if (pCurNode == pCurNode->pParent->arrSubNode.GetAt(i))
				{
					pCurNode->pParent->arrSubNode.RemoveAt(i);
					break;
				}
			}	
			delete pCurNode;
			arrNode.RemoveAt(0);
			nSizeArr = arrNode.GetSize();
			continue;
// 			return FALSE;
		}
	
		LARGE_INTEGER llCurSize = {0,0};
		LARGE_INTEGER llLeafSize = {0,0};
		CTreeNode* pChildNode = NULL;
		BOOL bRes = TRUE;
		do
		{
			pChildNode = new CTreeNode;
			ASSERT(NULL != pChildNode);
			//dir or file
			if (FindFileData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
			{
				if (IsDot(FindFileData.cFileName))
				{
					pCurNode->dwFileAttributes = FindFileData.dwFileAttributes;
					pCurNode->ftLastWriteTime = FindFileData.ftLastWriteTime;
					delete pChildNode;
					pChildNode = NULL;
				}
				else
				{
					pChildNode->csName = FindFileData.cFileName;
					pChildNode->dwFileAttributes = FindFileData.dwFileAttributes;
					pChildNode->ftLastWriteTime = FindFileData.ftLastWriteTime;
					pChildNode->pParent = pCurNode;
					pCurNode->arrSubNode.Add(pChildNode);	
					//add to queue
					arrNode.Add(pChildNode);
				}
			}
			else
			{
				pChildNode->csName = FindFileData.cFileName;
				pChildNode->dwFileAttributes = FindFileData.dwFileAttributes;
				pChildNode->ftLastWriteTime = FindFileData.ftLastWriteTime;
				pChildNode->dwNodeSizeHigh = FindFileData.nFileSizeHigh;
				pChildNode->dwNodeSizeLow = FindFileData.nFileSizeLow;
				llLeafSize.HighPart = pChildNode->dwNodeSizeHigh;
				llLeafSize.LowPart = pChildNode->dwNodeSizeLow;
				llCurSize.QuadPart += llLeafSize.QuadPart;
				pChildNode->pParent = pCurNode;
				pCurNode->arrLeaf.Add(pChildNode);
			}
			bRes = FindNextFile(hFind, &FindFileData);
		}
		while (bRes);	
		if (ERROR_NO_MORE_FILES != GetLastError())
		{
		}
		if (!FindClose(hFind))
		{
			continue;
// 			return FALSE;
		}

		//Set Current Node Size
		if (llCurSize.QuadPart>0)
		{
			LARGE_INTEGER llParentSize = {0,0};
			pCurNode->dwNodeSizeHigh = llCurSize.HighPart;
			pCurNode->dwNodeSizeLow = llCurSize.LowPart;
			CTreeNode* pParent = pCurNode->pParent;
			while (NULL != pParent)
			{
				llParentSize.HighPart = pParent->dwNodeSizeHigh;
				llParentSize.LowPart = pParent->dwNodeSizeLow;
				llParentSize.QuadPart += llCurSize.QuadPart;
				pParent->dwNodeSizeHigh = llParentSize.HighPart;
				pParent->dwNodeSizeLow = llParentSize.LowPart;
				pParent = pParent->pParent;
			}
		}
		//if have subNode then sublevel+1
		if (pCurNode->arrSubNode.GetSize()>0)
		{
			pCurNode->nSubLevel += 1;
			int nLevel = pCurNode->nSubLevel + 1;
			CTreeNode* pParent = pCurNode->pParent;
			while(NULL != pParent)
			{
				if (pParent->nSubLevel < nLevel)
				{
					pParent->nSubLevel = nLevel;
					nLevel++;
				}
				else
				{
					break;
				}
				pParent = pParent->pParent;
			}
		}
		arrNode.RemoveAt(0);
		nSizeArr = arrNode.GetSize();
		if (pCallbackFun)
		{
			ASSERT(NULL != lParam);
			pCallbackFun(m_pRootNode->dwNodeSizeHigh, m_pRootNode->dwNodeSizeLow, lParam);
		}
	}
	m_bTraversing = FALSE;

	return TRUE;
}

CString CTreeManager::RemoveBackSlash(CString& csPath)
{
	CString csRet(csPath);
	int nSize = csRet.GetLength();
	while((csRet.GetAt(nSize-1) == '\\')||(csRet.GetAt(nSize-1) == '*'))
	{
		csRet = csRet.Left(nSize-1);
		nSize = csRet.GetLength();
	}
	return csRet;
}

CString CTreeManager::GetFullPath(CTreeNode* pNode)
{
	ASSERT(NULL != pNode);
	CString csPath = pNode->csName;
	CTreeNode* pParent = pNode->pParent;
	while (pParent)
	{
		csPath = pParent->csName + _T("\\") + csPath;
		pParent = pParent->pParent;
	}
	return csPath;
}

BOOL CTreeManager::IsDot(CString csPath)
{
	if (csPath == _T(".") || csPath == _T(".."))
	{
		return TRUE;
	}
	return FALSE;
}

UINT CTreeManager::GetTreeLevel()
{
	ASSERT(NULL != m_pRootNode);
	return m_pRootNode->nSubLevel;
}

void CTreeManager::GetTreeSize(LARGE_INTEGER& llSize)
{
	ASSERT(NULL != m_pRootNode);
	llSize.HighPart = m_pRootNode->dwNodeSizeHigh;
	llSize.LowPart = m_pRootNode->dwNodeSizeLow;
}

void CTreeManager::CountChild(CTreeNode* pRootNode)
{
	
}
